//
// Created by cjh on 2021/5/11.
//

#ifndef RESOURCE_AIO_H
#define RESOURCE_AIO_H
#include <coroutine>
#include <vector>
#include <string>


class socket;


class async_io
{
public:
    /** It's a wrapper of system socket IO function.
     * support `co_await read()` and `co_await write()`
     *
     * int  read(void* ptr, size_t size, int flag);
     * int write(void* ptr, size_t size, int flag);
     *
     *  return :
     *       0 on close
     *      -1 on error
     *      >0 bytes read/write
     *
     * read._waiting is a trigger that guide you to resume current coroutine to continue read/write
     *
    **/

    //  async func -----------------------------------------------------------------------------------------------------
    class _io_base {
    protected:
        bool _waiting = false;
        //----args
        int flag = 0, result = -1;
        unsigned int size = 0;
        void *ptr = nullptr;
        //----
        class socket *sock = nullptr;

    public:
        explicit _io_base(class socket *sock):sock(sock) {}
        inline void stop() noexcept { _waiting = false, result = 0; }
        inline bool waiting() const noexcept { return _waiting; }
    };

    //  async func -----------------------------------------------------------------------------------------------------
    class _write : public _io_base {
    public:
        struct _write_return {
            [[nodiscard]] bool await_ready() const;
            [[nodiscard]] inline bool await_suspend(const std::coroutine_handle<> &) const noexcept { return true; }
            [[nodiscard]] int await_resume() const;
            _write *wr;
        };
        friend class async_io;
        explicit _write(class socket* sock): _io_base(sock) {}
        inline _write_return operator ()(void *_ptr, unsigned int _size, int _flag=0){
            ptr = _ptr, size = _size, flag = _flag;
            return _write_return{this};
        }
        template<typename T>
        inline _write_return operator ()(T& t) { return operator()(t.data(), t.size()); }
    } write;

    //  async func -----------------------------------------------------------------------------------------------------
    class _read : public _io_base {
    public:
        struct _read_return {
            [[nodiscard]] bool await_ready() const;
            [[nodiscard]] inline bool await_suspend(const std::coroutine_handle<> &) const noexcept { return true; }
            [[nodiscard]] int await_resume() const;

        _read *rd;
        };
        friend class async_io;
        explicit _read(class socket* sock): _io_base(sock) {}
        inline _read_return operator ()(void *_ptr, unsigned int _size, int _flag=0){
            ptr = _ptr, size = _size, flag = _flag;
            return _read_return{this};
        }
        template<typename T>
        inline _read_return operator ()(T& t) { return operator()(t.data(), t.size()); }
    } read;
    //  async func -----------------------------------------------------------------------------------------------------

    explicit async_io(class socket *sock) :read(sock), write(sock) {}

protected:
    inline void aio_init(class socket *sock) {
        read._waiting = false, read.result = -1;
        write._waiting = false, write.result = -1;
        read.sock = sock, write.sock = sock;
    }
};



#endif //RESOURCE_AIO_H
